#include "shell.h"
#include "ff.h"
#include <string.h>
//根目录
#define BASE_DIR   "c:/"
#define BASE_DIR1   "c:"
#define MAX_PATH_LEN 30
static char full_path[MAX_PATH_LEN];
/* 全局错误处理函数:解析FatFs错误码并输出原因*/
static void print_fresult_error(FRESULT res)
{
    switch (res) {
    case FR_OK:          printf("(操作成功)\r\n"); break;
    case FR_DISK_ERR:    printf("(底层磁盘I/O错误,可能SPI通信失败或Flash故障)\r\n"); break;
    case FR_INT_ERR:     printf("(内部逻辑错误,通常是配置错误或断言失败)\r\n"); break;
    case FR_NOT_READY:   printf("(设备未就绪,可能Flash未初始化或未挂载)\r\n"); break;
    case FR_NO_FILE:     printf("(文件不存在,检查文件名或路径是否正确)\r\n"); break;
    case FR_NO_PATH:     printf("(路径不存在,目录未创建或拼写错误)\r\n"); break;
    case FR_INVALID_NAME:printf("(文件名无效,包含*?:\"<>|等特殊字符)\r\n"); break;
    case FR_DENIED:      printf("(访问被拒绝,文件只读或目录满/非空)\r\n"); break;
    case FR_EXIST:       printf("(文件/目录已存在,创建模式冲突)\r\n"); break;
    case FR_INVALID_OBJECT: printf("(文件/目录对象无效,可能未正确打开)\r\n"); break;
    case FR_WRITE_PROTECTED: printf("(设备只读,Flash写保护未解除)\r\n"); break;
    case FR_INVALID_DRIVE: printf("(驱动器无效,如访问未挂载的分区)\r\n"); break;
    case FR_NOT_ENABLED: printf("(卷无工作区,配置错误或缓冲区不足)\r\n"); break;
    case FR_NO_FILESYSTEM: printf("(无有效文件系统,需先执行格式化)\r\n"); break;
    case FR_TIMEOUT:     printf("(访问超时,多线程未获取锁)\r\n"); break;
    case FR_LOCKED:      printf("(文件被锁定,其他操作未关闭文件)\r\n"); break;
    case FR_NOT_ENOUGH_CORE: printf("(内存不足,长文件名缓冲区分配失败)\r\n"); break;
    case FR_TOO_MANY_OPEN_FILES: printf("(打开文件数超限,需增大配置)\r\n"); break;
    case FR_INVALID_PARAMETER: printf("(参数无效,传入NULL指针或非法路径)\r\n"); break;
    default:             printf("(未知错误,参考ff.h手册)\r\n"); break;
    }
}

/**
 * @desc  : 拼接当前工作目录和目标路径
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : path - 待拼接的相对路径(NULL则返回当前目录)
 * @note  :
 */
static int join_path(const char* path)
{
    memset(full_path, 0, MAX_PATH_LEN);
    if (!path) {
        strcpy(full_path, BASE_DIR);
        return 1;
    }

    // 处理绝对路径(以"C:/"开头):直接使用绝对路径
    if (strncmp(path, BASE_DIR, strlen(BASE_DIR)) == 0 || strncmp(path, BASE_DIR1, strlen(BASE_DIR1)) == 0) {
        if (strlen(path) >= MAX_PATH_LEN) {
            printf("file path too long (max %d)\r\n", MAX_PATH_LEN);
            return -1;
        }
        strcpy(full_path, path);
        return 1;
    }

    // 拼接当前目录和相对路径
    size_t total_len = strlen(BASE_DIR) + strlen(path) + 1;
    if (total_len > MAX_PATH_LEN) {
        printf("file path too long (max %d), current %d\r\n", MAX_PATH_LEN, total_len);
        return -1;
    }
    strcpy(full_path, BASE_DIR);
    strcat(full_path, path);
    return 1;
}

/**
 * @desc  : 创建文件
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(argv[1]为文件名)
 * @return: int
 * @note  :
 */
int touch(int argc, char** argv)
{
    FIL file;
    FRESULT res;
    if (argc < 2) {
        printf("error! exp: touch a.txt\r\n");
        return 0;
    }
    if (join_path(argv[1]) == -1) {
        return 0;
    }
    printf("Creating file: %s\r\n", full_path);
    res = f_open(&file, full_path, FA_CREATE_NEW);
    f_close(&file);
    if (res == FR_OK) {
        printf("successful!\r\n");
    } else {
        print_fresult_error(res);
    }
    return 0;
}

/**
 * @desc  : 查看文件内容
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(argv[1]为文件名)
 * @return: int
 */
int echo(int argc, char** argv)
{
    if (argc < 2) {
        printf("error! exp: echo a.txt\r\n");
        return 0;
    }
    FIL file;
    FRESULT res;
    if (!join_path(argv[1])) return 0;
    char buffer[256];
    res = f_open(&file, full_path, FA_READ);
    if (res != FR_OK) {
        print_fresult_error(res);
        return 0;
    }
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        char* ret = f_gets(buffer, sizeof(buffer), &file);
        if (ret != NULL) {
            char* p = buffer;
            // 安全跳过开头的\0：限制在缓冲区范围内，避免越界
            while (p < buffer + sizeof(buffer) && *p == '\0') {
                p++;  // 仅在*p是\0时自增，非\0时不跳过
            }
            // 打印剩余有效内容（若p未越界）
            if (p < buffer + sizeof(buffer)) printf("%s", p);
        } else {
            if (f_error(&file)) {
                printf("\r\n读取文件错误!\r\n");
            } else {
                printf("\r\n-----FINISH-----\r\n");
            }
            break;
        }
    }
    f_close(&file);
    return 0;
}

/**
 * @desc  : 向文件写入数据
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(argv[1]为文件名,argv[2]为写入内容)
 * @return: int
 */
int cat(int argc, char** argv)
{
    if (argc < 3) {
        printf("error! exp: cat a.txt 123\r\n");
        return 0;
    }
    FIL file;
    FRESULT res;
    if (join_path(argv[1]) == -1)  return 0;
    res = f_open(&file, full_path, FA_WRITE | FA_OPEN_ALWAYS | FA_OPEN_APPEND);
    if (res != FR_OK) {
        print_fresult_error(res);
        return 0;
    }
    int num = f_printf(&file, "%s\r\n", argv[2]);
    if (num <= 0) {
        printf("write file error! please check");
    } else if ((num - 1) != (int)strlen(argv[2])) {
        printf("实际写入%d字节\r\n", num - 1);
    } else {
        printf("successful!\r\n");
    }
    f_close(&file);
    return 0;
}

/**
 * @desc  : 列出指定目录内容
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : path - 目录路径
 */
void list_directory_files(const char* path)
{
    FILINFO fno;
    DIR dir;
    FRESULT res;
    uint8_t file_count = 0;
    if (join_path(path) == -1) return;
    res = f_opendir(&dir, full_path);
    if (res != FR_OK) {
        print_fresult_error(res);
        return;
    }
    for (;;) {
        res = f_readdir(&dir, &fno);
        if (res != FR_OK) {
            print_fresult_error(res);
            break;
        }
        if (fno.fname[0] == 0) break;
        if ((fno.fname[0] == '.' && fno.fname[1] == '\0') ||
            (fno.fname[0] == '.' && fno.fname[1] == '.' && fno.fname[2] == '\0')) {
            continue;
        }
        file_count++;
        if (fno.fattrib & AM_DIR) {
            printf("%s/\r\n", fno.fname);
        } else {
            printf("%s\r\n", fno.fname);
        }
    }
    if (file_count == 0) {
        printf("Dirtory is empty\r\n");
    }
    f_closedir(&dir);
}

/**
 * @desc  : 列出目录命令(适配当前目录)
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(argv[1]为目录名,可选)
 * @return: int
 */
int ls(int argc, char** argv)
{
    if (argc == 1) {
        list_directory_files(NULL);
    } else {
        list_directory_files(argv[1]);
    }
    return 0;
}

/**
 * @desc  : 删除文件/目录命令(适配当前目录)
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(rm 文件名 或 rm -f 目录名)
 * @return: int
 */
int rm(int argc, char** argv)
{
    FRESULT res;
    if (argc < 2 || argc>3) {
        printf("error!,exp: rm a | rm -d dir(must empty)\r\n");
    }
    // rm a.txt
    if (argc == 2 && join_path(argv[1])) {
        res = f_unlink(full_path);
        if (res == FR_OK) {
            printf("successful!\r\n");
        } else {
            print_fresult_error(res);
        }
    }
    if (argc == 3 && strncmp(argv[1], "-d", strlen("-d")) == 0 && join_path(argv[2])) {
        res = f_unlink(full_path);
        if (res == FR_OK) {
            printf("successful!\r\n");
        } else {
            print_fresult_error(res);
        }
    }
    return 0;
}

/**
 * @desc  : 创建目录命令
 * @date  : 2025-11-18
 * @author: AnRui
 * @param : argc - 参数个数
 * @param : argv - 参数列表(argv[1]为目录名)
 * @return: int
 */
int mkdir(int argc, char** argv)
{
    FRESULT res;
    if (argc < 2) {
        printf("error! exp: mkdir a\r\n");
        return 0;
    }
    if (join_path(argv[1]) == -1)   return 0;
    res = f_mkdir(full_path);
    if (res == FR_OK) {
        printf("successful!\r\n");
    } else {
        print_fresult_error(res);
    }
    return 0;
}

static int test(int argc, char** argv)
{
    FIL file;
    FRESULT res;
    char buffer[256];
    res = f_open(&file, "c:/a.txt", FA_READ);
    if (res == FR_OK) {
        while (!f_eof(&file)) {
            //把缓冲区所有的数据都替换成0
            memset(buffer, 0, sizeof(buffer));
            if (f_gets(buffer, sizeof(buffer), &file) != NULL) {
                printf("%s", buffer); // 注意：f_gets已包含换行符
            }
        }
        f_close(&file); // 关闭已读取的文件
    } else {
        print_fresult_error(res);
    }
    return 0;
}
/* 命令注册 - 新增cd和pwd,更新其他命令描述适配当前目录 */
CLI_CMD_EXPORT(touch, "Create file in current dir: touch a.txt");
CLI_CMD_EXPORT(echo, "Show file content: echo a.txt");
CLI_CMD_EXPORT(cat, "Write data to file: cat a.txt 123");
CLI_CMD_EXPORT(ls, "List directory: ls (current) or ls dirname");
CLI_CMD_EXPORT(rm, "Delete file/dir: rm a.txt or rm _f dirname");
CLI_CMD_EXPORT(mkdir, "Create directory: mkdir a or mkdir a/b/c");
CLI_CMD_EXPORT(test, "test");
